#pragma once
#include <windows.h>
#include <stdint.h>
/*
 * Values below are taken from Wireguard Windows client
 * https://github.com/WireGuard/wireguard-go/blob/master/tun/wintun/ring_windows.go#L14
 */
#define WINTUN_RING_CAPACITY        0x800000
#define WINTUN_RING_TRAILING_BYTES  0x10000
#define WINTUN_MAX_PACKET_SIZE      0xffff
#define WINTUN_PACKET_ALIGN         4
 /* Memory alignment of packets and rings */
#define TUN_ALIGNMENT sizeof(ULONG)
#define TUN_ALIGN(Size) (((ULONG)(Size) + ((ULONG)TUN_ALIGNMENT - 1)) & ~((ULONG)TUN_ALIGNMENT - 1))
#define TUN_IS_ALIGNED(Size) (!((ULONG)(Size) & ((ULONG)TUN_ALIGNMENT - 1)))
/* Maximum IP packet size */
#define TUN_MAX_IP_PACKET_SIZE 0xFFFF
/* Maximum packet size */
#define TUN_MAX_PACKET_SIZE TUN_ALIGN(sizeof(TUN_PACKET_) + TUN_MAX_IP_PACKET_SIZE)
/* Minimum ring capacity. */
#define TUN_MIN_RING_CAPACITY 0x20000 /* 128kiB */
/* Maximum ring capacity. */
#define TUN_MAX_RING_CAPACITY 0x4000000 /* 64MiB */
/* Calculates ring capacity */
#define TUN_RING_CAPACITY(Size) ((Size) - sizeof(TUN_RING) - (TUN_MAX_PACKET_SIZE - TUN_ALIGNMENT))
/* Calculates ring offset modulo capacity */
#define TUN_RING_WRAP(Value, Capacity) ((Value) & (Capacity - 1))
#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)

#if 1
struct TUN_PACKET_
{

	ULONG size;

	UCHAR _Field_size_bytes_(size)
		data[];
};
#endif

#if 1
struct TUN_PACKET
{
	uint32_t size;
	UCHAR data[WINTUN_MAX_PACKET_SIZE];
};
#endif
/**
 * Wintun ring buffer
 * See https://github.com/WireGuard/wintun#ring-layout
 */
 //#pragma pack(push, 1)
struct tun_ring
{
	volatile ULONG head;
	volatile ULONG tail;
	volatile LONG alertable;
	UCHAR data[WINTUN_RING_CAPACITY + TUN_MAX_PACKET_SIZE - TUN_ALIGNMENT];
};

/**
 * Struct for ring buffers registration
 * See https://github.com/WireGuard/wintun#registering-rings
 */
struct tun_register_rings
{
	struct
	{
		ULONG ring_size;
		tun_ring* ring;
		HANDLE tail_moved;
	} send, receive;
};
struct TUN_PACKET_HEADER
{
	uint32_t size;
};

//#pragma pack(pop)